﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Lesson15
{
    internal class Program
    {
        public static bool isRunning = true; // 线程中止标识

        static object obj = new object();

        static void Main(string[] args)
        {
            #region 多线程
            // 先了解进程
            // 进程（Process）是计算机中的程序关于某数据集合上的一次运行活动，是系统进行资源分配和调度的一个独立单位（基本单位），是操作系统结构的基础。
            // 一个应用程序就是一个进程，进程之间相互独立运行，互不干扰，进程间也可以相互访问、操作

            // 线程：
            // 线程（Thread）是进程中的一个执行单元，是 CPU 调度和分配的基本单位，是程序执行的最小单位。一个进程可以包含多个线程。
            // 线程是操作系统能够运算调度的最小单位，包含在进程中，是进程中的实际运作单位
            // 一条线程指的是进程中一个单一顺序的控制流，一个进程可以并发多个线程
            // 我们目前写的程序，都在主线程中，简单理解线程：就是代码从上到下运行的一条“管道”

            // 多线程：通过代码开启新的线程，可以同时运行代码的多条“管道”，就叫多线程

            // 语法：
            // 线程类 Thread
            // 需要引用命名空间 using System.Threading
            // 声明一个新的线程  注意：线程执行的代码，需要封装到一个函数中
            //   新线程 将要执行的代码逻辑 被封装到一个函数语句块中
            Thread thread = new Thread(NewThreadLogic);

            // 启动线程
            thread.Start();

            // 设置为后台线程
            // 当前台线程都结束了，整个程序就结束了，即使还有后台线程在运行，后台线程不会防止应用程序的进程被终止掉
            // 如果不设置为后台线程，可能导致进程无法正常关闭
            // 新开的线程默认是前台线程，所以要设置为后台线程
            thread.IsBackground = true;

            // 关闭释放一个线程
            // 如果开启的线程中不是死循环，是能够结束的逻辑，那么不用刻意去关闭它
            //thread = null; // 这样就结束了
            // 但是如果是死循环，想要中止这个线程，有两种方式
            // 1、死循环中 bool 标识
            //isRunning = false;  // 将标识设置为 false


            // 2、使用线程的Abort方法，强制终止线程（注意：在.Net core版本中无法中止，会报错）
            //thread.Abort(); // 终止线程  会报错
            //thread = null;
            // 加try catch捕获异常
            //try
            //{
            //    thread.Abort(); 
            //    thread = null;
            //}
            //catch
            //{

            //}

            // 线程休眠
            //Thread.Sleep(1000);  // 传的是毫秒
            // 让哪个线程休眠，就在哪个线程执行


            // 线程之间共享数据
            // 多个线程使用的内存是共享的，都属于该应用程序（进程）
            // 所以要注意，当多线程 同时操作同一片内存区域时，可能会出问题
            // 可以通过加锁的形式避免问题

            // 两个线程同时执行以下程序，需要加锁
            // lock：当我们在多个线程中想要访问同样的东西 进行逻辑处理时

            // 语法：lock(引用类型对象)
            while (true)
            {
                // 使用  必须要传一个引用对象
                lock(obj) 
                {
                    Console.SetCursorPosition(0, 0);  // 设置光标位置
                    Console.ForegroundColor = ConsoleColor.Green;
                    Console.Write("●");  // 输入法 v1 可以调出来
                }
                // 窗口程序（控制台）
                //Console.SetCursorPosition(0, 0);  // 设置光标位置
                //Console.ForegroundColor = ConsoleColor.Green;
                //Console.Write("●");  // 输入法 v1 可以调出来
            }

            // 多线程对于我们的意义
            // 可以用多线程专门处理一些复杂耗时的逻辑
            // 比如  寻路、网络通信等

            #endregion
        }

        // 新开线程执行的代码逻辑 被封装到一个函数语句块中
        static void NewThreadLogic()
        {
            // 线程执行的代码逻辑
            //for (int i = 0; i < 10; i++)
            //{
            //    Thread.Sleep(1000); // 让线程休眠1秒
            //    Console.WriteLine("新线程执行中" + i);
            //    //Thread.Sleep(1000); // 让线程休眠1秒
            //}
            //while (true)
            //{
            //    Console.WriteLine("循环");
            //}
            //while (isRunning)
            //{
            //    Console.WriteLine("中止标识");
            //}
            while (true)
            {
                // 窗口程序
                //Console.SetCursorPosition(10, 5);  // 设置光标位置
                //Console.ForegroundColor = ConsoleColor.Blue;
                //Console.Write("■");
                lock (obj)   // 锁同一个引用对象
                {
                    Console.SetCursorPosition(10, 5);  // 设置光标位置
                    Console.ForegroundColor = ConsoleColor.Blue;
                    Console.Write("■");
                }
            }
        }
    }
}
